package com.langshixiaobai.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.langshixiaobai.admin.common.constant.UserConstant;
import com.langshixiaobai.admin.common.convention.exception.ClientException;
import com.langshixiaobai.admin.dao.entity.UserDO;
import com.langshixiaobai.admin.dao.entity.UserInfoDTO;
import com.langshixiaobai.admin.dto.req.UserLoginReqDTO;
import com.langshixiaobai.admin.dto.req.UserRegisterReqDTO;
import com.langshixiaobai.admin.dao.mapper.UserMapper;
import com.langshixiaobai.admin.dto.req.UserUpdateReqDTO;
import com.langshixiaobai.admin.dto.resp.UserLoginRespDTO;
import com.langshixiaobai.admin.service.GroupService;
import com.langshixiaobai.admin.service.UserService;
import lombok.RequiredArgsConstructor;
import org.redisson.api.*;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
//
import java.util.UUID;

import static com.langshixiaobai.admin.common.constant.RedisCacheConstant.LOCK_USER_REGISTER_KEY;
import static com.langshixiaobai.admin.common.enums.UserErrorCodeEnum.*;

@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper,UserDO> implements UserService {


    private final RBloomFilter<String> rBloomFilter;
    private final RedissonClient redissonClient;
    private final UserMapper userMapper;
    private final GroupService groupService;

    @Override
    public void register(UserRegisterReqDTO requestParam) {
        if (hasUsername(requestParam.getUsername())) {
            LambdaQueryWrapper<UserDO> wrapper = Wrappers.lambdaQuery(UserDO.class).eq(UserDO::getUsername, requestParam.getUsername());
            UserDO userDO = userMapper.selectOne(wrapper);
            if(!BeanUtil.isEmpty(userDO)){
                throw new ClientException(USER_NAME_EXIST);
            }
        }
        RLock lock = redissonClient.getLock(LOCK_USER_REGISTER_KEY + requestParam.getUsername());
        try {
            if (lock.tryLock()) {
                UserDO userDO = BeanUtil.copyProperties(requestParam, UserDO.class);
               try {
                   int insert = userMapper.insert(userDO);
                   if (insert < 1) {
                       throw new ClientException(USER_SAVE_ERROR);
                   }
               }catch (DuplicateKeyException ex){
                   throw new ClientException(USER_EXIST);
               }
                //添加到布隆布隆过滤器中
               rBloomFilter.add(requestParam.getUsername());
               //为用户绑定分组
                groupService.saveGroup("默认分组");
                return;
            }
                throw new ClientException(USER_SAVE_ERROR);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public UserLoginRespDTO userLogin(UserLoginReqDTO requestParam) {
        String username = requestParam.getUsername();
        String password = requestParam.getPassword();
        if(username == null){
            throw new ClientException(USER_NULL);
        }
        if(password == null){
            throw new ClientException(USER_NULL);
        }

        LambdaQueryWrapper<UserDO> wrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getUsername, username)
                .eq(UserDO::getPassword, password);
        UserDO userDO = baseMapper.selectOne(wrapper);
        UUID uuid = UUID.randomUUID();
        String token = uuid.toString().replace("-","");
        UserInfoDTO userInfoDTO = UserInfoDTO.builder()
                .userId(String.valueOf(userDO.getId()))
                .username(userDO.getUsername())
                .token(token)
                .build();
        //TODO 用map做的
        RMap<String, String> map = redissonClient.getMap(UserConstant.USER_Login_KEY);
        map.put(token, JSONUtil.toJsonStr(userInfoDTO));
        // 设置过期时间
//        map.expire(2, TimeUnit.DAYS);
        return UserLoginRespDTO.builder().token(token).build();
    }

    @Override
    public void updateUser(UserUpdateReqDTO requestParam) {
        // TODO 验证当前用户名是否为登录用户
        LambdaUpdateWrapper<UserDO> updateWrapper = Wrappers.lambdaUpdate(UserDO.class)
                .eq(UserDO::getUsername, requestParam.getUsername());

        baseMapper.update(BeanUtil.copyProperties(requestParam, UserDO.class), updateWrapper);

    }

    @Override
    public UserDO getUserInfo(String username) {

        LambdaQueryWrapper<UserDO> wrapper = Wrappers.lambdaQuery(UserDO.class).eq(UserDO::getUsername, username);
        return userMapper.selectOne(wrapper);
    }

    // 判断布隆过滤器中是否存在当前用户
    public Boolean hasUsername(String username){
        return rBloomFilter.contains(username);
    }

    @Override
    public Boolean checkLogin(String username, String token) {
        RMap<String, String> map = redissonClient.getMap(UserConstant.USER_Login_KEY);
        String json = map.get(token);
        UserDO userDO = JSONUtil.toBean(json, UserDO.class);
        if(!userDO.getUsername().equals(username)){
            return false;
        }
        return true;
    }
}
